﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using OpenQuarters.WebQuarters.Utils;

namespace OpenQuarters.WebQuarters.Core
{
    public partial class User : CMSEntity<User, string>
    {
        public override System.Linq.Expressions.Expression<Func<User, bool>> GetIDSelector(string ID)
        {
            return e => e.UserId == ID;
        }

        public override string GetKey(User Entity)
        {
            return Entity.UserId;
        }

        public override bool IsNew(User Entity)
        {
            return Table.FirstOrDefault(e => e.UserId == Entity.UserId) == null;
        }

        public override string ToString()
        {
            return this.UserId;
        }

        private List<Role> roles = null;

        public List<Role> Roles
        {
            get
            {
                if (roles == null)
                {
                    roles = UserRole.Table.Where(e => e.UserId == this.UserId).Select(e => e.Role).ToList();
                }

                return roles;
            }
        }

        public PermissionCollection AllPermissions
        {
            get
            {
                return ContextItem.GetItem("User.AllPermissions." + this.UserId, () => AllPermissions_get());
            }
        }

        private PermissionCollection AllPermissions_get()
        {
            var roleIds = Roles.Select(e => e.RoleId).ToList();
            return new PermissionCollection(Permission.Table.Where(e => roleIds.Contains(e.RoleId) || e.UserId == this.UserId).ToList());
        }

        public bool HasPermission(string permission, string value)
        {
            return HasPermission(new Permission()
            {
                Name = permission
            }, value);
        }

        public bool HasPermission(Permission permission, string value)
        {
            if (!this.IsActive)
            {
                return false;
            }
            else
            {
            if (this.Roles.FirstOrDefault(e => e.RoleId == Role.SuperAdminRoleId) != null)
            {
                return true;
            }
            foreach (var e in AllPermissions)
            {
                if (e.Name == permission.Name && e.Value == value)
                {
                    return true;
                }
            }
            return false;
            }
        }

        public bool HasPermission(Permission permission)
        {
            return HasPermission(permission, permission.Value);
        }

        public bool HasRole(string roleId)
        {
            Role role = new Role();
            role.RoleId = roleId;
            return HasRole(role);
        }

        public bool HasRole(Role role)
        {
            foreach (var r in Roles)
            {
                if (r.RoleId == role.RoleId)
                {
                    return true;
                }
            }
            return false;
        }

        public List<UserMessage> UserMessages
        {
            get { return UserMessage.Table.Where(e => e.UserId == this.UserId).ToList(); }
        }

        [Newtonsoft.Json.JsonProperty]
        public bool IsAuthenticated
        {
            get { return UserRoles.Where(e => e.RoleId != Role.GuestRoleId).Count() > 0; }
        }

        [Newtonsoft.Json.JsonProperty]
        public string json_UserId
        {
            get { return this.UserId; }
        }

        public const string CookieKey = "__WQUserToken";
        public const string SessionKey = "__CurrentUserId";
        public const string ContextKey = "__CurrentUserContext";
        public const string LastFailedURLSessionKey = "__CurrentUserLastFailedURL";

        public string LastFailedURL
        {
            get { return SessionItem.GetItem(LastFailedURLSessionKey, () => "/"); }
            set { SessionItem.SetItem(LastFailedURLSessionKey, value); }
        }

        private static User current
        {
            get { return ContextItem.GetItem<User>(ContextKey, () => null); }
            set { ContextItem.SetItem(ContextKey, value); }
        }

        public static User Current
        {
            get
            {
                if (current == null)
                {
                    // Check session first
                    if (Oracle.Session[SessionKey] != null)
                    {
                        current = User.Load((string)Oracle.Session[SessionKey]);
                    }

                    if (current == null)
                    {
                        // Check cookie
                        if (Oracle.Request.Cookies[CookieKey] != null)
                        {
                            UserToken token = UserToken.Load(Oracle.Request.Cookies[CookieKey].Value);
                            if (token != null)
                            {
                                current = User.Load(token.UserId);
                                token.Delete();
                                if (current != null)
                                {
                                    SetupUserToken();
                                }
                            }
                        }
                    }

                    if (current == null)
                    {
                        // Create new guest user
                        CMSEnvironment.LoggingMode = LoggingMode.Off;
                        current = new User()
                        {
                            UserId = GeneralUtils.GetGuid(),
                            VerificationCode = Guid.NewGuid().ToString()

                        }.Save();
                        User.AddToRole(current.UserId, Role.Default.RoleId);
                        SetupUserToken();
                        CMSEnvironment.LoggingMode = null;
                    }
                }
                return current;
            }
            set
            {
                Oracle.Session[SessionKey] = value == null ? "" : value.UserId;
                current = null;
            }
        }

        public static UserRole AddToRole(string UserId, string RoleId)
        {
            return new UserRole()
            {
                UserId = UserId,
                RoleId = RoleId
            }.Save();
        }

        public static UserToken SetupUserToken()
        {
            UserToken newToken = new UserToken()
            {
                UserId = Current.UserId,
                UserTokenId = GeneralUtils.GetGuid(),
            };
            newToken.Save();
            Oracle.Request.Cookies.Remove(CookieKey);
            Oracle.Response.AppendCookie(new HttpCookie(CookieKey)
            {
                HttpOnly = true,
                Value = newToken.UserTokenId,
                Expires = DateTime.Now.AddYears(2)
            });

            return newToken;
        }

        public bool Login(string UserId, string Password)
        {
            var u = Table.FirstOrDefault(e => e.UserId == UserId && e.Password == GeneralUtils.MD5Encrypt(Password) && e.IsActive == true);
            if (u != null)
            {
                Current = u;
                return true;
            }
            return false;
        }

        public void Logout()
        {
            Current = null;
        }

        public static void BasicSetup()
        {
            User u = new User()
            {
                UserId = "admin",
                Password = "21232f297a57a5a743894a0e4a801fc3",
                IsActive = true,
                VerificationCode = Guid.NewGuid().ToString()
            }.Save();

            AddToRole("admin", Role.SuperAdminRoleId);
            u.AddPermission(Core.Permissions.Admin.AddWorkflowComment, Role.SuperAdminRoleId);
        }

        public Permission AddPermission(Permission Permission, string RoleId)
        {
            return new Permission()
            {
                RoleId = RoleId,
                Name = Permission.Name,
                Value = Permission.Value
            }.Save();
        }
    }
}
